package comviva_2014.SmartMapper;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

public class Main2 {

	public static void main(String[] args) throws IOException {
		String fileName = args[0];
		if (args.length == 1) {
			System.out.println("READY");
			return;
		}

		File f = new File(fileName);

		if (f.exists() == false) {
			System.out.println("FAILURE");
			return;
		}

		String[] id_split = args[1].split(",");

		List<String> txn_ids = new ArrayList<String>();
		List<String> ref_ids = new ArrayList<String>();

		for (String ids : id_split) {
			String[] s = ids.split("=");
			if (s[0].equals("T"))
				txn_ids.add(s[1]);
			else if (s[0].equals("R"))
				ref_ids.add(s[1]);
		}

		if (txn_ids.size() == 0 && ref_ids.size() == 0) {
			System.out.println("FAILURE");
			return;
		}

		solve(fileName, txn_ids, ref_ids);

	}

	private static void solve(String fileName, List<String> txn_ids,
			List<String> ref_ids) throws IOException {

		RandomAccessFile aFile = new RandomAccessFile(fileName, "r");
		FileChannel inChannel = aFile.getChannel();
		long fileSize = inChannel.size();
		MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY,
				0, fileSize);

		int nLines = ((int) fileSize / (67 * 100000));

		long txn_hash = 0;
		long ref_hash = 0;
		for (int nl = 0; nl < nLines; nl++) {
			LongHashMap txn_mp = new LongHashMap(100000);
			LongHashMap ref_mp = new LongHashMap(100000);

			for (int j = 0; j < 100000; j++) {
				txn_hash = 5381;

				byte[] txn_bb = new byte[32];
				for (int p = 0; p < 32; p++) {
					txn_bb[p] = buffer.get();
					txn_hash = ((txn_hash << 5) + txn_hash) + txn_bb[p];

				}
				buffer.get();

				ref_hash = 5381;
				byte[] ref_bb = new byte[32];
				for (int p = 0; p < 32; p++) {
					ref_bb[p] = buffer.get();
					ref_hash = ((ref_hash << 5) + ref_hash) + ref_bb[p];
				}
				
				txn_mp.put(txn_hash, ref_bb);
				ref_mp.put(ref_hash, txn_bb);
			}
			
		}

	}

	public String getTransactionID(String RefID) {
		return "";
	}

	public String getRefID(String TransactionID) {
		return "";
	}

	public static void readFile(String fileName) throws IOException {

		RandomAccessFile aFile = new RandomAccessFile(fileName, "r");
		FileChannel inChannel = aFile.getChannel();
		long fileSize = inChannel.size();
		MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY,
				0, fileSize);

		int nLines = ((int) fileSize / (67 * 100000));
		;

		int pos = 0;

		int nl = 0;
		long txn_hash = 0;
		long ref_hash = 0;
		HashSet test = new HashSet();
		for (int i = 0; i < nLines; i++) {
			LongHashMap txn_mp = new LongHashMap(100000);

			for (int j = 0; j < 100000; j++) {

				txn_hash = 5381;

				for (int p = 0; p < 32; p++) {
					txn_hash = ((txn_hash << 5) + txn_hash) + buffer.get();
				}
				buffer.get();
				// System.out.println(txn_hash);
				if (test.add(txn_hash) == false)
					System.out.println("false");

				ref_hash = 5381;

				for (int p = 0; p < 32; p++) {
					ref_hash = ((ref_hash << 5) + ref_hash) + buffer.get();
				}
				buffer.get();

		//		txn_mp.put(txn_hash, nl);
				// System.out.println(new String(dst));
				pos += 67;
				buffer.position(pos);
				nl++;

			}
			// System.out.println(txn_mp.size);

		}
		System.out.println("Set: " + test.size());
		System.out.println(nl);

		// System.out.println(buffer.limit());
		/*
		 * long wcl = 0; long txn_hash = 0; long ref_hash = 0;
		 * 
		 * for (int i = 0; i < fileSize / 6; i++) {
		 * 
		 * System.out.printf("%3d  ", i); byte[] dst = new byte[66];
		 * buffer.get(dst);
		 * 
		 * i += 66; buffer.position(i + 1); System.out.println(new String(dst));
		 * // System.out.println(djb_hash(dst, 0, 32)); //
		 * System.out.println(new String(Arrays.copyOfRange(dst, 0, 32))); //
		 * System.out.println(new String(Arrays.copyOfRange(dst, 33, 66)));
		 * 
		 * // txnMap.put(djb_hash(dst, 0, 32), wcl); // System.out.print(wcl +
		 * ", "); wcl++; } ;
		 */

		inChannel.close();
		aFile.close();
		// System.out.println(cc);

	}

	static long djb_hash(byte[] buff, int start, int end) {
		long hash = 5381;

		for (int i = start; i <= end; i++) {
			hash = ((hash << 5) + hash) + buff[i];
		}

		return hash;
	}

	static class LongHashMap {
		static final int DEFAULT_INITIAL_CAPACITY = 16;
		static final int MAXIMUM_CAPACITY = 1 << 30;
		static final float DEFAULT_LOAD_FACTOR = 0.75f;
		Entry[] table;
		int size;
		int threshold;
		final float loadFactor;

		public LongHashMap(int initialCapacity) {
			this.loadFactor = 0.75f;
			threshold = (int) (initialCapacity * loadFactor);
			table = new Entry[initialCapacity];
		}

		public boolean put(long key, byte[] value) {
			int hash = hash(key);
			int i = indexFor(hash, table.length);
			for (Entry e = table[i]; e != null; e = e.next) {
				if (e.hash == hash && e.key == key) {
					e.value = value;
					return false;
				}
			}

			addEntry(hash, key, value, i);
			return true;
		}

		static int hash(long hh) {
			int h = (int) (hh ^ (hh >>> 32));
			h ^= (h >>> 20) ^ (h >>> 12);
			return h ^ (h >>> 7) ^ (h >>> 4);
		}

		static int indexFor(int h, int length) {
			return h & (length - 1);
		}

		void addEntry(int hash, long key, byte[] value, int bucketIndex) {
			Entry e = table[bucketIndex];
			table[bucketIndex] = new Entry(hash, key, value, e);
			if (size++ >= threshold)
				resize(2 * table.length);
		}

		void resize(int newCapacity) {
			Entry[] oldTable = table;
			int oldCapacity = oldTable.length;
			if (oldCapacity == MAXIMUM_CAPACITY) {
				threshold = Integer.MAX_VALUE;
				return;
			}

			Entry[] newTable = new Entry[newCapacity];
			transfer(newTable);
			table = newTable;
			threshold = (int) (newCapacity * loadFactor);
		}

		void transfer(Entry[] newTable) {
			Entry[] src = table;
			int newCapacity = newTable.length;
			for (int j = 0; j < src.length; j++) {
				Entry e = src[j];
				if (e != null) {
					src[j] = null;
					do {
						Entry next = e.next;
						int i = indexFor(e.hash, newCapacity);
						e.next = newTable[i];
						newTable[i] = e;
						e = next;
					} while (e != null);
				}
			}
		}

		final Object get(long key) {
			int hash = hash(key);
			for (Entry e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
				if (e.hash == hash && e.key == key)
					return e.value;
			}
			return null;

		}

		static class Entry {
			final long key;
			byte[] value;
			Entry next;
			final int hash;

			Entry(int h, long k, byte[] v, Entry n) {
				next = n;
				key = k;
				value = v;
				hash = h;
			}

			public final long getKey() {
				return key;
			}

			public final byte[] getValue() {
				return value;
			}

			public final byte[] setValue(byte[] newValue) {
				byte[] oldValue = value;
				value = newValue;
				return oldValue;
			}

			public final boolean equals(Object o) {
				if (!(o instanceof Entry))
					return false;
				Entry e = (Entry) o;
				if (this.key == e.key) {
					if (Arrays.equals(this.value, e.getValue()))
						return true;
				}
				return false;
			}

		}
	}
}
